/*|¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯|
  | Métodos Numéricos I - Tarefa.3 - Questão.1 |
  |           (Sistemas de Equações)           |
  |____________________________________________|*/

// É Linux ou é Windows?
#ifdef linux      // Sistema Operacional: Linux.
    #define sistema_operacional 0
#else
    #ifdef _WIN32 // Sistema Operacional: Windows.
        #define sistema_operacional 1
    #endif
#endif
// Vixe! Não é nenhum dos 2...
#ifndef sistema_operacional
    #error Sistema Operacional desconhecido!!! So rodo no Linux ou no Windows!!!
#endif

/*** LIXUX - INCLUDES E DEFINES ***/
#if (sistema_operacional == 0)
    #include "Extras/fuba_linux.h"
#endif

/*** WINDOWS - INCLUDES E DEFINES ***/
#if (sistema_operacional == 1)
    #include "Extras/fuba_win.h"
#endif

/*** DEFINES do programa ***/
// NADA!

/*** INCLUDES do programa ***/
#include <iostream>
#include <vector>

// Classes:
#include "Classes/matriz.h"
#include "Classes/gauss.h"
#include "Classes/gauss_pp.h"
#include "Classes/gauss_jordan.h"
#include "Classes/lu.h"
using namespace std;

// Função para criar uma cópia do sistema (matriz "A" e vetor "b"):
void sistema_copiar(matriz *mat_original, matriz **mat_copia, vector<float> *vet_original, vector<float> *vet_copia)
{
    // Deletando a matriz copia (caso exista!):
    if ((*mat_copia) != NULL)
        (*mat_copia)->~matriz();
    // Instanciando a matriz copia:
    (*mat_copia) = new matriz();
    // Copiando a matriz original para a matriz copia:
    (*mat_copia)->copiar(mat_original);
    // Copiando o vetor original para o vetor copia:
    (*vet_copia) = (*vet_original);
}

// Função para imprimir o sistema (matriz e vetor):
void sistema_imprimir(matriz *s, vector<float> *c)
{
    if ((s == NULL) || (c == NULL))
        return;
    for(int i=0 ; i<(s->get_linhas()) ; i++)
    {
        for(int j=0 ; j<(s->get_colunas()) ; j++)
            cout <<(s->get_aij(i,j))<<"\t";
        cout<<" = "<<(*c)[i]<<endl;
    }
}

int main(void) // PRINCIPAL //
{
    // Variáveis do MAIN:
    char escolha = '\0';
    matriz *A = NULL;
    matriz *A_copia = NULL;
    vector<float> b;
    vector<float> b_copia;

/// MATRIZES PARA TESTE: ///

/*********************************
    A = new matriz(3);

    A->set_aij(0,0,3);
    A->set_aij(0,1,2);
    A->set_aij(0,2,4);

    A->set_aij(1,0,1);
    A->set_aij(1,1,1);
    A->set_aij(1,2,2);

    A->set_aij(2,0,4);
    A->set_aij(2,1,3);
    A->set_aij(2,2,-2);

    b.push_back(1);
    b.push_back(2);
    b.push_back(3);
/********************************/

/*********************************
    A = new matriz(4);
	A->set_todos_aij(0);

    A->set_aij(0,0,3);
    A->set_aij(0,1,2);
    A->set_aij(0,2,1);
    A->set_aij(0,3,-1);

    A->set_aij(1,1,1);
    A->set_aij(1,3,3);

    A->set_aij(2,1,-3);
    A->set_aij(2,2,-5);
    A->set_aij(2,3,7);

    A->set_aij(3,1,2);
    A->set_aij(3,2,4);

    b.push_back(5);
    b.push_back(6);
    b.push_back(7);
    b.push_back(15);
/********************************/

/*********************************
    A = new matriz(2);

    A->set_aij(0,0,1);
    A->set_aij(0,1,2);

    A->set_aij(1,0,3);
    A->set_aij(1,1,1);

    b.push_back(4);
    b.push_back(7);
/********************************/

    do{// MENU PRINCIPAL //
        limpar_tela();
        cout <<"#=============================================================#"<<endl;
        cout <<"#        [Metodos Numericos I - Tarefa.3 - Questao.1]         #"<<endl;
        cout <<"#                   (Sistemas de Equacoes)                    #"<<endl;
        cout <<"#=============================================================#"<<endl;
        cout <<"> Escolha:"<<endl;
        cout <<"  (i) Inserir o sistema na forma matricial;"<<endl;
        cout <<"  (e) Exibir sistema;"<<endl;
        cout <<"\n  * Resolver o sistema por:"<<endl;
        cout <<"  (1) Metodo de Gauss;"<<endl;
        cout <<"  (2) Metodo de Gauss (com pivotacao parcial);"<<endl;
        cout <<"  (3) Metodo de Gauss-Jordan;"<<endl;
        cout <<"  (4) Fatoracao LU;"<<endl;
        cout <<"  (X) Sair do programa."<<endl;
        escolha = ler_tecla();
        switch(escolha)
        {
            case 'I': /// Inserir sistema ///
            {
                int n;
                float valor;
                limpar_tela();
                cout <<"+---------------------+"<<endl;
                cout <<"|  Inserir o sistema  |"<<endl;
                cout <<"+---------------------+"<<endl;
                cout << "* Insira o tamanho do sistema: ";
                cin >> n;
                if (n <= 0)
                    cout << "  > Tamanho do sistema e invalido!!!"<<endl;
                else
                {
                    // Desalocando o vetor "b":
                    b.clear();
                    // Deletando a matriz "A":
                    if (A != NULL)
                        A->~matriz();
                    // Instanciando a matriz "A":
                    A = new matriz(n);

                    cout << "\n* Leitura da matriz \"A\":"<<endl;
                    for (int i=0; i<n; i++)
                    {
                        for (int j=0; j<n; j++)
                        {
                            cout << "> Insira elemento a["<<i<<","<<j<<"] = ";
                            cin >> valor;
                            A->set_aij(i,j,valor);
                        }
                    }

                    cout << "\n* Leitura do vetor \"b\":"<<endl;
                    for (int i=0; i<n; i++)
                    {
                        cout << "> Insira elemento b["<<i<<"] = ";
                        cin >> valor;
                        b.push_back(valor);
                    }
                }
                cout<<endl;
                pausar();
                break;
            }
            case 'E': /// Exibir sistema ///
            {
                limpar_tela();
                cout <<"+------------------+"<<endl;
                cout <<"|  Exibir sistema  |"<<endl;
                cout <<"+------------------+"<<endl;
                sistema_imprimir(A,&b);
                cout<<endl;
                pausar();
                break;
            }
            case '1': /// Método de Gauss ///
            {
                /// === Criando uma cópia do sistema === ///
                sistema_copiar(A,&A_copia,&b,&b_copia);
                limpar_tela();
                cout <<"+-------------------+"<<endl;
                cout <<"|  Metodo de Gauss  |"<<endl;
                cout <<"+-------------------+"<<endl;

                cout <<"* Sistema (inicial):"<<endl;
                sistema_imprimir(A_copia,&b_copia);

                // Instanciando Gauss:
                gauss G(A_copia,&b_copia);
                // Checando se deu tudo certo na resolução do sistema:
                if (G.resolver_sistema() == true)
                {
                    cout <<"\n* Sistema (final):"<<endl;
                    G.imprimir_sistema();
                    // Checando se deu tudo certo na retro-substituição:
                    if (G.retro_substituicao() == true)
                    {
                        cout <<"\n* Solucao do sistema:"<<endl;
                        G.vetor_X_imprimir();
                    }
                }
                cout <<endl;
                pausar();
                break;
            }
            case '2': /// Método de Gauss (com pivotação parcial) ///
            {
                /// === Criando uma cópia do sistema === ///
                sistema_copiar(A,&A_copia,&b,&b_copia);
                limpar_tela();
                cout <<"+-------------------------------------------+"<<endl;
                cout <<"|  Metodo de Gauss (com pivotacao parcial)  |"<<endl;
                cout <<"+-------------------------------------------+"<<endl;

                cout <<"* Sistema (inicial):"<<endl;
                sistema_imprimir(A_copia,&b_copia);

                // Instanciando Gauss (com pivotação parcial):
                gauss_pp Gpp(A_copia,&b_copia);
                // Checando se deu tudo certo na resolução do sistema:
                if (Gpp.resolver_sistema() == true)
                {
                    cout <<"\n* Sistema (final):"<<endl;
                    Gpp.imprimir_sistema();
                    // Checando se deu tudo certo na retro-substituição:
                    if (Gpp.retro_substituicao() == true)
                    {
                        cout <<"\n* Solucao do sistema:"<<endl;
                        Gpp.vetor_X_imprimir();
                    }
                }
                cout <<endl;
                pausar();
                break;
            }
            case '3': /// Método de Gauss-Jordan ///
            {
                /// === Criando uma cópia do sistema === ///
                sistema_copiar(A,&A_copia,&b,&b_copia);
                limpar_tela();
                cout <<"+--------------------------+"<<endl;
                cout <<"|  Metodo de Gauss-Jordan  |"<<endl;
                cout <<"+--------------------------+"<<endl;

                cout <<"* Sistema (inicial):"<<endl;
                sistema_imprimir(A_copia,&b_copia);

                // Instanciando Gauss-Jordan:
                gauss_jordan GJ(A_copia,&b_copia);
                // Checando se deu tudo certo na resolução do sistema:
                if (GJ.resolver_sistema() == true)
                {
                    cout <<"\n* Sistema (final):"<<endl;
                    GJ.imprimir_sistema();
                    // Checando se deu tudo certo na substituição imediata:
                    if (GJ.substituicao_imediata() == true)
                    {
                        cout <<"\n* Solucao do sistema:"<<endl;
                        GJ.vetor_X_imprimir();
                    }
                }
                cout <<endl;
                pausar();
                break;
            }
            case '4': /// Fatoração LU ///
            {
                /// === Criando uma cópia do sistema === ///
                sistema_copiar(A,&A_copia,&b,&b_copia);
                limpar_tela();
                cout <<"+----------------+"<<endl;
                cout <<"|  Fatoracao LU  |"<<endl;
                cout <<"+----------------+"<<endl;

                cout <<"* Sistema (inicial):"<<endl;
                sistema_imprimir(A_copia,&b_copia);

                // Instanciando Fatoração LU:
                lu LU(A_copia,&b_copia);
                // Checando se deu tudo certo na resolução do sistema:
                if ((LU.resolver_sistema() == true) && (LU.calcular_Lyb() == true) && (LU.calcular_Uxy() == true))
                {
                    cout <<"\n* Sistema L.y=b:"<<endl;
                    LU.imprimir_sistema_Lyb();

                    cout <<"\n* Solucao do sistema L.y=b:"<<endl;
                    LU.vetor_Y_imprimir();

                    cout <<"\n* Sistema U.x=y:"<<endl;
                    LU.imprimir_sistema_Uxy();

                    cout <<"\n* Solucao do sistema U.x=y:"<<endl;
                    LU.vetor_X_imprimir();
                }
                cout<<endl;
                pausar();
                break;
            }
        }// fim do "switch(escolha)" //
      }while(escolha!='X');// fim do "MENU PRINCIPAL" //
    return(0);
}
